package com.example.service;

import com.example.entity.Dongtai;
import com.example.mapper.DongtaiMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DataAnalysisService {

    @Autowired
    private DongtaiMapper dongtaiMapper;

    @Autowired
    private PythonScriptService pythonScriptService;

    @Value("${analysis.temp-dir}")
    private String tempDir;

    private final ObjectMapper objectMapper = new ObjectMapper();

    // 存储中间结果的路径信息
    private String allDataCsvPath = null;           // 所有数据的CSV路径
    private String selectedFeaturesDataPath = null; // 21个字段数据路径
    private String imputedDataPath = null;          // 插补后数据路径
    private List<String> top20Features = null;     // 前20个重要特征列表

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private FieldMappingService fieldMappingService;

    /**
     * 第一次相关性分析
     */
    public Map<String, Object> performFirstCorrelationAnalysis(String algorithm) throws Exception {
        log.info("开始第一次相关性分析，算法：{}", algorithm);

        // 验证算法参数
        if (!Arrays.asList("anova", "correlation").contains(algorithm)) {
            throw new IllegalArgumentException("不支持的相关性分析算法：" + algorithm);
        }

        // 从数据库读取数据
        List<Dongtai> data = dongtaiMapper.selectAll();
        if (data.isEmpty()) {
            throw new RuntimeException("数据库中没有数据");
        }

        // 转换为CSV文件
        this.allDataCsvPath = convertToCSV(data, "all_data");
        log.info("所有数据已转换为CSV: {}", allDataCsvPath);

        // 调用Python脚本（现在会自动处理5个必须字段）
        Map<String, Object> result;
        if (algorithm.equals("anova")) {
            result = pythonScriptService.executeFirstAnovaScript(allDataCsvPath);
        } else {
            result = pythonScriptService.executeFirstCorrelationScript(allDataCsvPath);
        }

        if (!"success".equals(result.get("status"))) {
            throw new RuntimeException("第一次相关性分析失败: " + result.get("message"));
        }

        // 获取前20个重要特征和必须字段包含情况
        this.top20Features = (List<String>) result.get("top_20_features");
        List<String> mandatoryIncluded = (List<String>) result.get("mandatory_included");
        List<String> missingMandatory = (List<String>) result.get("missing_mandatory");

        log.info("选出前20个重要特征: {}", top20Features);
        log.info("必须字段包含情况: {}", mandatoryIncluded);
        if (!missingMandatory.isEmpty()) {
            log.warn("缺失的必须字段: {}", missingMandatory);
        }

        // 提取选中特征的数据（包含qyb，因为现在需要在第二次分析中包含qyb）
        this.selectedFeaturesDataPath = extractSelectedFeatures(data, top20Features);
        log.info("20个字段数据已保存到: {}", selectedFeaturesDataPath);

        Map<String, Object> finalResult = new HashMap<>();
        finalResult.put("status", "success");
        finalResult.put("algorithm", algorithm);
        finalResult.put("algorithmName", algorithm.equals("anova") ? "方差分析" : "皮尔逊相关系数");
        finalResult.put("dataCount", data.size());
        finalResult.put("top_20_features", top20Features);
        finalResult.put("mandatory_fields", Arrays.asList("rcyl", "rcql", "ljcyl", "ljcql", "qyb"));
        finalResult.put("mandatory_included", mandatoryIncluded);
        finalResult.put("missing_mandatory", missingMandatory);
        finalResult.put("target_variable", "qyb");
        finalResult.put("result", result);
        finalResult.put("timestamp", System.currentTimeMillis());

        return enrichResultWithChineseNames(finalResult);
    }
    /**
     * 第二次相关性分析 - 支持算法选择
     * 使用第一次分析得到的21个字段数据
     */
    public Map<String, Object> performSecondCorrelationAnalysis(String algorithm) throws Exception {
        log.info("开始第二次相关性分析，算法：{}", algorithm);

        // 验证算法参数
        if (!Arrays.asList("anova", "correlation").contains(algorithm)) {
            throw new IllegalArgumentException("不支持的相关性分析算法：" + algorithm);
        }

        // 检查前置条件
        if (selectedFeaturesDataPath == null || !Files.exists(Paths.get(selectedFeaturesDataPath))) {
            throw new RuntimeException("请先完成第一次相关性分析");
        }

        if (top20Features == null || top20Features.isEmpty()) {
            throw new RuntimeException("缺少第一次分析的特征列表");
        }

        // 根据算法选择调用不同的Python脚本
        Map<String, Object> result;
        try {
            if (algorithm.equals("anova")) {
                String selectedFeaturesJson = objectMapper.writeValueAsString(top20Features);
                result = pythonScriptService.executeSecondAnovaScript(selectedFeaturesDataPath, selectedFeaturesJson);
            } else {
                String selectedFeaturesJson = objectMapper.writeValueAsString(top20Features);
                result = pythonScriptService.executeSecondCorrelationScript(selectedFeaturesDataPath, selectedFeaturesJson);
            }

            if (result == null || result.isEmpty()) {
                log.error("Python脚本返回空结果");
                throw new RuntimeException("Python脚本执行失败：返回结果为空");
            }

            if (!"success".equals(result.get("status"))) {
                String errorMsg = (String) result.get("message");
                log.error("第二次相关性分析失败: {}", errorMsg);
                throw new RuntimeException("第二次相关性分析失败: " + errorMsg);
            }

        } catch (Exception e) {
            log.error("第二次相关性分析执行异常", e);
            throw new RuntimeException("第二次相关性分析失败: " + e.getMessage(), e);
        }

        Map<String, Object> finalResult = new HashMap<>();
        finalResult.put("status", "success");
        finalResult.put("algorithm", algorithm);
        finalResult.put("algorithmName", algorithm.equals("anova") ? "方差分析" : "皮尔逊相关系数");
        finalResult.put("selected_features", top20Features);
        finalResult.put("result", result);
        finalResult.put("timestamp", System.currentTimeMillis());

        return enrichResultWithChineseNames(finalResult);
    }


    /**
     * 数据插补 - 支持算法选择
     * 使用21个字段数据进行插补
     */
    public Map<String, Object> performDataImputation(String algorithm) throws Exception {
        log.info("开始数据插补，算法：{}", algorithm);

        // 验证算法参数
        if (!Arrays.asList("iterative", "rf").contains(algorithm)) {
            throw new IllegalArgumentException("不支持的插补算法：" + algorithm);
        }

        // 检查前置条件：确保已完成第一次相关性分析
        if (selectedFeaturesDataPath == null || !Files.exists(Paths.get(selectedFeaturesDataPath))) {
            throw new RuntimeException("请先完成第一次相关性分析");
        }

        // 根据算法选择调用不同的Python脚本
        Map<String, Object> result;
        if (algorithm.equals("iterative")) {
            result = pythonScriptService.executeImputationScript(selectedFeaturesDataPath);
        } else {
            result = pythonScriptService.executeRfImputationScript(selectedFeaturesDataPath);
        }

        if (!"success".equals(result.get("status"))) {
            throw new RuntimeException("数据插补失败: " + result.get("message"));
        }

        // 保存插补后数据路径，供后续步骤使用
        this.imputedDataPath = (String) result.get("imputed_data_path");
        log.info("插补完成，数据已保存到: {}", imputedDataPath);

        // 将插补后的数据保存到数据库
        String tableName = algorithm.equals("iterative") ? "dongtai_iterative" : "dongtai_rf";
        saveImputedDataToDatabase(imputedDataPath, tableName, result);

        Map<String, Object> finalResult = Map.of(
                "status", "success",
                "algorithm", algorithm,
                "algorithmName", algorithm.equals("iterative") ? "IterativeImputer插补" : "随机森林插补",
                "selected_features", top20Features,
                "result", result,
                "timestamp", System.currentTimeMillis()
        );

        return enrichResultWithChineseNames(finalResult);
    }


    /**
     * 数据扩充 - 支持算法选择
     * 使用插补后的数据进行扩充
     */
    public Map<String, Object> performDataAugmentation(String algorithm, Map<String, Object> params) throws Exception {
        log.info("开始数据扩充，算法：{}", algorithm);

        // 验证算法参数
        if (!Arrays.asList("noise", "smote").contains(algorithm)) {
            throw new IllegalArgumentException("不支持的数据扩充算法：" + algorithm);
        }

        // 检查前置条件：确保已完成数据插补
        if (imputedDataPath == null || !Files.exists(Paths.get(imputedDataPath))) {
            throw new RuntimeException("请先完成数据插补");
        }

        // 获取目标样本数，默认5000
        int targetSamples = (Integer) params.getOrDefault("targetSamples", 5000);

        // 根据算法选择调用不同的Python脚本
        Map<String, Object> result;
        if (algorithm.equals("noise")) {
            result = pythonScriptService.executeAugmentationScript(imputedDataPath, targetSamples);
        } else {
            result = pythonScriptService.executeSmoteAugmentationScript(imputedDataPath, targetSamples);
        }

        if (!"success".equals(result.get("status"))) {
            throw new RuntimeException("数据扩充失败: " + result.get("message"));
        }

        // 将扩充后的数据保存到数据库
        String csvPath = (String) result.get("augmented_data_path");
        String tableName = algorithm.equals("noise") ? "dongtai_noise" : "dongtai_smote";
        saveAugmentedDataToDatabase(csvPath, tableName, result);

        Map<String, Object> finalResult = Map.of(
                "status", "success",
                "algorithm", algorithm,
                "algorithmName", algorithm.equals("noise") ? "噪声扩充" : "SMOTE扩充",
                "selected_features", top20Features,
                "target_samples_requested", targetSamples,
                "result", result,
                "timestamp", System.currentTimeMillis()
        );

        return enrichResultWithChineseNames(finalResult);
    }

    /**
     * 完整分析流程 - 支持每步算法选择
     */
    public Map<String, Object> performCompleteAnalysis(String firstCorrelationAlg,
                                                       String secondCorrelationAlg, String imputationAlg, String augmentationAlg)
            throws Exception {

        log.info("开始完整分析流程");
        log.info("第一次相关性分析：{}，第二次相关性分析：{}，插补：{}，扩充：{}",
                firstCorrelationAlg, secondCorrelationAlg, imputationAlg, augmentationAlg);

        Map<String, Object> results = new HashMap<>();
        long startTime = System.currentTimeMillis();

        try {
            // 第一次相关性分析
            Map<String, Object> firstCorr = performFirstCorrelationAnalysis(firstCorrelationAlg);
            results.put("firstCorrelationAnalysis", firstCorr);

            // 第二次相关性分析
            Map<String, Object> secondCorr = performSecondCorrelationAnalysis(secondCorrelationAlg);
            results.put("secondCorrelationAnalysis", secondCorr);

            // 数据插补
            Map<String, Object> imputation = performDataImputation(imputationAlg);
            results.put("dataImputation", imputation);

            // 数据扩充
            Map<String, Object> augmentationParams = Map.of("targetSamples", 5000);
            Map<String, Object> augmentation = performDataAugmentation(augmentationAlg, augmentationParams);
            results.put("dataAugmentation", augmentation);

            results.put("status", "success");
            results.put("message", "完整分析流程执行成功");
            results.put("algorithms", Map.of(
                    "firstCorrelation", firstCorrelationAlg,
                    "secondCorrelation", secondCorrelationAlg,
                    "imputation", imputationAlg,
                    "augmentation", augmentationAlg
            ));

        } catch (Exception e) {
            log.error("完整分析流程执行失败", e);
            results.put("status", "error");
            results.put("message", "分析过程中发生错误：" + e.getMessage());
        }

        results.put("executionTime", System.currentTimeMillis() - startTime);
        results.put("timestamp", System.currentTimeMillis());

        return enrichResultWithChineseNames(results);
    }

    private void saveImputedDataToDatabase(String csvPath, String tableName, Map<String, Object> imputationResult) {
        try {
            List<String> columns = new ArrayList<>();
            try (Reader reader = Files.newBufferedReader(Paths.get(csvPath));
                 CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) {
                columns = new ArrayList<>(csvParser.getHeaderMap().keySet());
            }

            // 构建建表SQL（不包含id字段）
            StringBuilder createSql = new StringBuilder("CREATE TABLE IF NOT EXISTS " + tableName + " (");
            for (String col : columns) {
                createSql.append("`").append(col).append("` DOUBLE,");
            }

            // 添加插补算法标识字段
            if (tableName.contains("iterative")) {
                createSql.append("`imputation_method` VARCHAR(50) DEFAULT 'IterativeImputer',");
            } else {
                createSql.append("`imputation_method` VARCHAR(50) DEFAULT 'RandomForest',");
            }

            // 添加时间戳字段，去掉最后的逗号
            createSql.append("`imputation_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");

            // 删除已存在的表并重新创建
            jdbcTemplate.execute("DROP TABLE IF EXISTS " + tableName);
            jdbcTemplate.execute(createSql.toString());

            // 构建插入SQL
            String insertSql = "INSERT INTO " + tableName + " (" +
                    String.join(",", columns.stream().map(col -> "`" + col + "`").collect(Collectors.toList())) +
                    ", imputation_method) VALUES (" +
                    columns.stream().map(c -> "?").collect(Collectors.joining(",")) + ",?)";

            // 批量插入数据
            List<Object[]> batchArgs = new ArrayList<>();
            int totalRows = 0;
            String imputationMethod = tableName.contains("iterative") ? "IterativeImputer" : "RandomForest";

            try (Reader reader = Files.newBufferedReader(Paths.get(csvPath));
                 CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) {

                for (CSVRecord record : csvParser) {
                    Object[] row = new Object[columns.size() + 1]; // +1 for method

                    for (int i = 0; i < columns.size(); i++) {
                        String value = record.get(columns.get(i));
                        if (value == null || value.trim().isEmpty()) {
                            row[i] = null;
                        } else {
                            try {
                                row[i] = Double.valueOf(value);
                            } catch (NumberFormatException e) {
                                row[i] = null;
                            }
                        }
                    }

                    row[columns.size()] = imputationMethod;
                    batchArgs.add(row);
                    totalRows++;

                    // 分批处理，避免内存问题
                    if (batchArgs.size() >= 1000) {
                        jdbcTemplate.batchUpdate(insertSql, batchArgs);
                        batchArgs.clear();
                        log.info("已插入 {} 行数据到表 {}", totalRows, tableName);
                    }
                }

                // 处理剩余数据
                if (!batchArgs.isEmpty()) {
                    jdbcTemplate.batchUpdate(insertSql, batchArgs);
                }
            }

            log.info("插补数据已成功保存到数据库表: {}，共 {} 行数据", tableName, totalRows);

        } catch (Exception e) {
            log.error("保存插补数据到数据库失败", e);
            throw new RuntimeException("保存插补数据失败: " + e.getMessage());
        }
    }



    private void saveAugmentedDataToDatabase(String csvPath, String tableName, Map<String, Object> augmentationResult) {

        try {
            List<String> columns = new ArrayList<>();
            try (Reader reader = Files.newBufferedReader(Paths.get(csvPath));
                 CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) {
                columns = new ArrayList<>(csvParser.getHeaderMap().keySet());
            }

            StringBuilder createSql = new StringBuilder("CREATE TABLE IF NOT EXISTS " + tableName + " (");
            for (String col : columns) {
                createSql.append("`").append(col).append("` DOUBLE,");
            }

            if (tableName.contains("smote")) {
                createSql.append("`smote_applied` BOOLEAN DEFAULT TRUE,");
            } else {
                createSql.append("`noise_level` FLOAT,");
            }
            createSql.append("`augmentation_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");

            jdbcTemplate.execute("DROP TABLE IF EXISTS " + tableName);
            jdbcTemplate.execute(createSql.toString());

            String insertSql = "INSERT INTO " + tableName + " (" +
                    String.join(",", columns) +
                    (tableName.contains("smote") ? ", smote_applied" : ", noise_level") +
                    ") VALUES (" +
                    columns.stream().map(c -> "?").collect(Collectors.joining(",")) + ",?)";

            List<Object[]> batchArgs = new ArrayList<>();
            try (Reader reader = Files.newBufferedReader(Paths.get(csvPath));
                 CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) {

                for (CSVRecord record : csvParser) {
                    Object[] row = new Object[columns.size() + 1];
                    for (int i = 0; i < columns.size(); i++) {
                        row[i] = Double.valueOf(record.get(columns.get(i)));
                    }
                    if (tableName.contains("smote")) {
                        row[columns.size()] = true;
                    } else {
                        row[columns.size()] = augmentationResult.get("noise_level_used");
                    }
                    batchArgs.add(row);
                }
            }

            jdbcTemplate.batchUpdate(insertSql, batchArgs);
            log.info("扩充数据已成功保存到数据库表: {}", tableName);

        } catch (Exception e) {
            log.error("保存扩充数据到数据库失败", e);
            throw new RuntimeException("保存扩充数据失败: " + e.getMessage());
        }
    }

    private String convertToCSV(List<Dongtai> data, String filePrefix) throws IOException {
        List<String> numericFields = getNumericFields();

        Files.createDirectories(Paths.get(tempDir));

        String csvPath = Paths.get(tempDir, filePrefix + "_" + System.currentTimeMillis() + ".csv").toString();

        try (PrintWriter writer = new PrintWriter(new FileWriter(csvPath, false), true)) {
            writer.println(String.join(",", numericFields));

            for (Dongtai entity : data) {
                List<String> values = new ArrayList<>();
                for (String field : numericFields) {
                    Object value = getFieldValue(entity, field);
                    values.add(value != null ? value.toString() : "");
                }
                writer.println(String.join(",", values));
            }
        }

        log.info("CSV文件已生成: {}, 包含 {} 行数据, {} 个字段", csvPath, data.size(), numericFields.size());
        return csvPath;
    }

    private String extractSelectedFeatures(List<Dongtai> allData, List<String> selectedFeatures) throws IOException {
        Files.createDirectories(Paths.get(tempDir));

        String csvPath = Paths.get(tempDir, "selected_features_" + System.currentTimeMillis() + ".csv").toString();

        try (PrintWriter writer = new PrintWriter(new FileWriter(csvPath, false), true)) {
            writer.println(String.join(",", selectedFeatures));

            for (Dongtai entity : allData) {
                List<String> values = new ArrayList<>();
                for (String field : selectedFeatures) {
                    Object value = getFieldValue(entity, field);
                    values.add(value != null ? value.toString() : "");
                }
                writer.println(String.join(",", values));
            }
        }

        log.info("{}个字段数据已提取到CSV: {}, 包含 {} 行数据", selectedFeatures.size(), csvPath, allData.size());
        return csvPath;
    }

    private List<String> getNumericFields() {
        List<String> numericFields = new ArrayList<>();
        Field[] fields = Dongtai.class.getDeclaredFields();

        for (Field field : fields) {
            Class<?> fieldType = field.getType();
            if (fieldType == Double.class || fieldType == double.class ||
                    fieldType == Float.class || fieldType == float.class ||
                    fieldType == Integer.class || fieldType == int.class ||
                    fieldType == Long.class || fieldType == long.class) {
                numericFields.add(field.getName());
            }
        }

        return numericFields;
    }

    private Object getFieldValue(Object entity, String fieldName) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(entity);
        } catch (Exception e) {
            log.warn("获取字段值失败: {}", fieldName);
            return null;
        }
    }


    /**
     * 为分析结果添加中文字段映射
     */
    private Map<String, Object> enrichResultWithChineseNames(Map<String, Object> result) {
        if (result == null) {
            return result;
        }

        try {
            // 检查 fieldMappingService 是否可用
            if (fieldMappingService == null) {
                log.warn("FieldMappingService 未初始化，跳过字段映射");
                return result;
            }

            // 如果传入的是不可变 Map，创建一个可变的副本
            Map<String, Object> mutableResult;
            try {
                // 尝试添加一个测试键来检查是否可变
                result.put("__test__", "test");
                result.remove("__test__");
                mutableResult = result; // 如果没有异常，说明是可变的
            } catch (UnsupportedOperationException e) {
                // 如果抛出异常，说明是不可变的，创建可变副本
                mutableResult = new HashMap<>(result);
            }

            // 处理 top_20_features（重要特征列表）
            if (mutableResult.containsKey("top_20_features")) {
                Object featuresObj = mutableResult.get("top_20_features");
                if (featuresObj instanceof List) {
                    List<String> features = (List<String>) featuresObj;
                    Map<String, String> featureNames = new LinkedHashMap<>();

                    for (String feature : features) {
                        try {
                            String chineseName = fieldMappingService.getChineseFieldName(feature);
                            featureNames.put(feature, chineseName);
                        } catch (Exception e) {
                            log.warn("获取字段 {} 的中文名称失败: {}", feature, e.getMessage());
                            featureNames.put(feature, feature); // 使用原名称作为备选
                        }
                    }

                    mutableResult.put("feature_chinese_names", featureNames);
                }
            }

            // 处理 selected_features
            if (mutableResult.containsKey("selected_features")) {
                Object featuresObj = mutableResult.get("selected_features");
                if (featuresObj instanceof List) {
                    List<String> features = (List<String>) featuresObj;
                    Map<String, String> featureNames = new LinkedHashMap<>();

                    for (String feature : features) {
                        try {
                            String chineseName = fieldMappingService.getChineseFieldName(feature);
                            featureNames.put(feature, chineseName);
                        } catch (Exception e) {
                            featureNames.put(feature, feature);
                        }
                    }

                    mutableResult.put("selected_features_chinese_names", featureNames);
                }
            }

            // 处理嵌套的 result 对象
            if (mutableResult.containsKey("result") && mutableResult.get("result") instanceof Map) {
                Map<String, Object> nestedResult = (Map<String, Object>) mutableResult.get("result");
                mutableResult.put("result", enrichResultWithChineseNames(nestedResult));
            }

            return mutableResult;

        } catch (Exception e) {
            log.error("添加中文字段映射时出错: {}", e.getMessage(), e);
            // 出错时返回原结果的可变副本
            return new HashMap<>(result);
        }
    }


}
